/****************************************************************
irrEventManager
Copyright (C) 2007-2008 Keith Holbrook
This file is part of "irrEventManager".
For conditions of distribution and use, see copyright notice in irrEventManagerr.h


the "CEventRecEx" and "CEventRecExT" classes were influenced by the article
"Delegates in a standard C++ way" by Ben Chan,
which can be read here: http://www.codeproject.com/KB/cpp/delegates_std.aspx
at the "Code Projects" website.
*****************************************************************/


#ifndef __SEVENT_REC_EX_H
#define __SEVENT_REC_EX_H

#include "IEventRecEx.h"


namespace irr
{

    typedef bool ( *pfEvRecCB)(const SEvent&,IEventRecEx*);

    struct SEventRecBase : public virtual IEventRecEx
    {

        SEventRecBase (void* _caller,void* _obj,void* _userData,s32 _id)
                :caller(_caller),obj(_obj),id(_id),userData(_userData)//,runOnce(0)
                {}

//        virtual ~SEventRecBase ()
//        {
//           // DEBUG_PRINT("SEventRecBase dest\n");
//        }

        virtual bool doEvent(const SEvent& e)=0;

        virtual void* getCaller()
        {
            return caller;
        }

         virtual void setCaller(void* s)
        {
            caller = s;
        }

//        virtual bool getRunOnce()
//        {
//            return runOnce;
//        }
//
//        virtual void setRunOnce(bool b)
//        {
//            runOnce = b;
//        }

        virtual void* getObj()
        {
            return obj;
        }

        virtual void setObj(void* o)
        {
            obj =o;
        }

        virtual void* getData()
        {
            return userData;
        }

        virtual void setData(void* d)
        {
            userData =d;
        }

        virtual s32 getID()
        {
            return id;
        }

        virtual void setID(s32 i)
        {
            id =i;
        }

protected:
        ///reserved for gui elements (in gui Events only)
        void*  caller;

        ///reserved for user object to call callback on
        void*  obj;

        ///reserved for callback id
        s32 id;

        ///for user data
        void*  userData;

       // bool   runOnce;


    };


    struct SEventRecEx :public SEventRecBase //, public virtual IEventRecEx
    {

        SEventRecEx (void* _caller,pfEvRecCB pf,void* _obj=0,void* _userData=0,s32 _id=-1)
                :SEventRecBase(_caller,_obj,_userData,_id),cb(pf){}

//        ~SEventRecEx ()
//        {
//            DEBUG_PRINT("SEventRecEx destroyed\n");
//        }

        virtual bool doEvent(const SEvent& e)
        {
            if (cb)
                return cb(e,this);
            return 0;

        }

protected:
        pfEvRecCB cb;


    };


    template<class T>
    struct SEventRecExT : public SEventRecBase//, public virtual IEventRecEx
    {
        typedef bool ( T::*pfEvRecCB2)(const SEvent&,IEventRecEx*);
        // bool  (T::*pfEvRecEx2)(const SEvent& e,IEventRecEx*);

        SEventRecExT(void* _caller,pfEvRecCB2 pf,void* _obj,void* _userData=0,s32 _id=-1)
                :SEventRecBase(_caller,_obj,_userData,_id),cb(pf)
        { }

//        ~SEventRecEx2()
//        {
//            DEBUG_PRINT("SEventRecEx2 destroyed\n");
//        }

        virtual bool doEvent(const SEvent& e)
        {
            if (obj && cb) //DEBUG_PRINT("SEventRecEx2 doEvent called\n");
                if (((reinterpret_cast<T*>(obj))->*cb )(e,this))
                    return 1;

            return 0;
        }

protected:
        pfEvRecCB2 cb;

    };



/// helpers
     inline bool  addEvent(IEventManager* m,EEVENT_TYPE t,void* caller,pfEvRecCB cb,void* obj=0,void* dat=0,s32 id=-1)
     {
         return m->getEvent(t)->add(new SEventRecEx(caller,cb,obj,dat,id));
     }

     inline bool  addGuiEvent(IEventManager* m,gui::EGUI_EVENT_TYPE t,gui::IGUIElement* el,pfEvRecCB cb,void* obj=0,void* dat=0,s32 id=-1)
     {
         return m->getGuiEvent(t)->add(new SEventRecEx(el,cb,obj,dat,id));
     }

///helpers for classes
     template<class T>
     inline  bool  addEventT(IEventManager* m,EEVENT_TYPE t,void* caller,bool  (T::*pf)(const SEvent& e,IEventRecEx*),T* obj=0,void* dat=0,s32 id=-1)
     {
         return m->getEvent(t)->add(new SEventRecExT<T>(caller,pf,obj,dat,id));
     }

     template<class T>
     inline bool  addGuiEventT(IEventManager* m,gui::EGUI_EVENT_TYPE t,gui::IGUIElement* el,bool  (T::*pf)(const SEvent& e,IEventRecEx*),T* obj,void* dat=0,s32 id=-1)
     {
         return m->getGuiEvent(t)->add(new SEventRecExT<T>(el,pf,obj,dat,id));
     }



}
#endif // __IEVENT_REC_EX_H
